/**************************************************************************************************
  Filename:       ota.c
  Revised:        
  Revision:       

  Description:    This file contains the OTA sample application
                  

**************************************************************************************************/

/*********************************************************************
 * INCLUDES
 */
#include "sdk_config.h"
#include "ll.h"
#include "ll_common.h"
#include "hci.h"
#include "OSAL.h"
#include "ll_def.h"
#include "hci_tl.h"
#include "bcomdef.h"
#include "OSAL_PwrMgr.h"
//#include "OnBoard.h"
#include "gatt.h"
#include "hci.h"

#include "gapgattserver.h"
#include "gattservapp.h"

#include "ota_service.h"
#include "ota_protocol.h"
#include "ota_flash.h"

#include "peripheral.h"
#include "gapbondmgr.h"
#include "devinfoservice.h"

#include "ota.h"
#include "log.h"
#include "flash.h"
#include "global_config.h"
#include "common.h"
/*********************************************************************
 * MACROS
 */

/*********************************************************************
 * CONSTANTS
 */

// How often to perform periodic event
#define OTA_PERIODIC_EVT_PERIOD                   100
 

#define DEFAULT_DISCOVERABLE_MODE             GAP_ADTYPE_FLAGS_GENERAL
///< Default passcode
#define DEFAULT_PASSCODE					0

// Length of bd addr as a string
#define B_ADDR_STR_LEN                        15

/*********************************************************************
 * TYPEDEFS
 */


/*********************************************************************
 * GLOBAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL FUNCTIONS
 */

/*********************************************************************
 * LOCAL VARIABLES
 */
static uint8 ota_TaskID;   // Task ID for internal task/event processing

static gaprole_States_t gapProfileState = GAPROLE_INIT;

// GAP - SCAN RSP data (max size = 31 bytes)
static uint8 scanRspData[] =
{
    ///< connection interval range
    0x05,	///< length of this data
    GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
    LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),	///< 100ms
    HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),
    LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),	///< 1s
    HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),

    ///< Tx power level
    0x02,	///< length of this data
    GAP_ADTYPE_POWER_LEVEL,
    0		///< 0dBm
};

// GAP - Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertisting)
static uint8 advertData[] =
{
	// Flags; this sets the device to use limited discoverable
	// mode (advertises for 30 seconds at a time) instead of general
	// discoverable mode (advertises indefinitely)
	0x02,   // length of this data
	GAP_ADTYPE_FLAGS,
	DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

	0x03,  //Manufacture data
	GAP_ADTYPE_MANUFACTURER_SPECIFIC,
	0xa7,  //company ID: 0x06A7(chipsea)
	0x06,
};

///< GAP GATT Attributes
static uint8 attDeviceName[GAP_DEVICE_NAME_LEN] = DEVICE_NAME;

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static void otaApp_ProcessOSALMsg( osal_event_hdr_t *pMsg );
static void peripheralStateNotificationCB( gaprole_States_t newState );
static void performPeriodicTask( void );
char *bdAddr2Str( uint8 *pAddr );

/*********************************************************************
 * PROFILE CALLBACKS
 */

// GAP Role Callbacks
static gapRolesCBs_t oatApp_PeripheralCBs =
{
    peripheralStateNotificationCB,  // Profile State Change Callbacks
    NULL       // When a valid RSSI is readed from controller (not used by application)
};
#if (DEFAULT_GAPBOND_MGR_ENABLE==1)
//GAP Bond Manager Callbacks, add 2017-11-15
static gapBondCBs_t simpleBLEPeripheral_BondMgrCBs =
{
  NULL,		///< Passcode callback (not used by application)
  NULL		///< Pairing / Bonding state Callback (not used by application)
};
#endif

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/*********************************************************************
 * @fn      otaApp_Init
 *
 * @brief   Initialization function for the Simple BLE Peripheral App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notificaiton ... ).
 *
 * @param   task_id - the ID assigned by OSAL.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void otaApp_Init( uint8 task_id )
{
    ota_TaskID = task_id;
//	volatile uint8_t * pubaddr = (volatile uint8_t*)0x1fff11f9;
   
    // Setup the GAP
    VOID GAP_SetParamValue( TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL );
  
    // Setup the GAP Peripheral Role Profile
    {
        // device starts advertising upon initialization
        uint8 initial_advertising_enable = TRUE;

        uint8 enable_update_request = DEFAULT_ENABLE_UPDATE_REQUEST;
        uint8 advChnMap = GAP_ADVCHAN_37 | GAP_ADVCHAN_38 | GAP_ADVCHAN_39; 
        
        // By setting this to zero, the device will go into the waiting state after
        // being discoverable for 30.72 second, and will not being advertising again
        // until the enabler is set back to TRUE
        uint16 gapRole_AdvertOffTime = 0;
    
        uint16 desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
        uint16 desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
        uint16 desired_slave_latency = DEFAULT_DESIRED_SLAVE_LATENCY;
        uint16 desired_conn_timeout = DEFAULT_DESIRED_CONN_TIMEOUT;
		
        uint8 advType =LL_ADV_CONNECTABLE_UNDIRECTED_EVT;// LL_ADV_NONCONNECTABLE_UNDIRECTED_EVT;//LL_ADV_SCANNABLE_UNDIRECTED_EVT;//LL_ADV_CONNECTABLE_LDC_DIRECTED_EVT;//;    // it seems a  bug to set GAP_ADTYPE_ADV_NONCONN_IND = 0x03
        GAPRole_SetParameter( GAPROLE_ADV_EVENT_TYPE, sizeof( uint8 ), &advType );
        // set adv channel map
        GAPRole_SetParameter(GAPROLE_ADV_CHANNEL_MAP, sizeof(uint8), &advChnMap);        

        // Set the GAP Role Parameters
        GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable );
        GAPRole_SetParameter( GAPROLE_ADVERT_OFF_TIME, sizeof( uint16 ), &gapRole_AdvertOffTime );

		uint8  advData[B_MAX_ADV_LEN];
		uint8 offset;
		//set scan_rsp information
		offset = 0;
		GAPRole_EncodeAdvDeviceName(advData, &offset, B_MAX_ADV_LEN, attDeviceName, osal_strlen((char *)attDeviceName));
		osal_memcpy(advData+offset, scanRspData, sizeof(scanRspData));
		GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, offset + sizeof ( scanRspData ), advData );
		
		//set adv_data information
		osal_memcpy(advData, advertData, sizeof(advertData));
		offset = sizeof(advertData);
		GAPRole_EncodeAdvDeviceAddr(advData, &offset, B_MAX_ADV_LEN);
		GAPRole_SetParameter( GAPROLE_ADVERT_DATA, offset, advData );

        GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &enable_update_request );
        GAPRole_SetParameter( GAPROLE_MIN_CONN_INTERVAL, sizeof( uint16 ), &desired_min_interval );
        GAPRole_SetParameter( GAPROLE_MAX_CONN_INTERVAL, sizeof( uint16 ), &desired_max_interval );
        GAPRole_SetParameter( GAPROLE_SLAVE_LATENCY, sizeof( uint16 ), &desired_slave_latency );
        GAPRole_SetParameter( GAPROLE_TIMEOUT_MULTIPLIER, sizeof( uint16 ), &desired_conn_timeout );
    }

    // Set the GAP Characteristics
    GGS_SetParameter( GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName );

    // Set advertising interval
    {
        uint16 advInt = DEFAULT_DESIRED_ADV_INTERVAL;	///< actual time = advInt * 625us

        GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, advInt );
        GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, advInt );
        GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, advInt );
        GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, advInt );
    }
#if(DEFAULT_GAPBOND_MGR_ENABLE==1)
    // Setup the GAP Bond Manager, add 2017-11-15
    {
        uint32 passkey = DEFAULT_PASSCODE;
        uint8 pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
        uint8 mitm = TRUE;
        uint8 ioCap = GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT;
        uint8 bonding = TRUE;
        GAPBondMgr_SetParameter( GAPBOND_DEFAULT_PASSCODE, sizeof ( uint32 ), &passkey );
        GAPBondMgr_SetParameter( GAPBOND_PAIRING_MODE, sizeof ( uint8 ), &pairMode );
        GAPBondMgr_SetParameter( GAPBOND_MITM_PROTECTION, sizeof ( uint8 ), &mitm );
        GAPBondMgr_SetParameter( GAPBOND_IO_CAPABILITIES, sizeof ( uint8 ), &ioCap );
        GAPBondMgr_SetParameter( GAPBOND_BONDING_ENABLED, sizeof ( uint8 ), &bonding );
    }
#endif
    // Initialize GATT attributes
    GGS_AddService( GATT_ALL_SERVICES );            // GAP
    GATTServApp_AddService( GATT_ALL_SERVICES );    // GATT attributes
    DevInfo_AddService();                           // Device Information Service
	otaProtocol_init();

	#if (1)
    {
        uint8_t mtuSet = 247;
        llInitFeatureSet2MPHY(TRUE);
        llInitFeatureSetDLE(TRUE);
        ATT_SetMTUSizeMax(mtuSet);
        LOG("[2Mbps | DLE | MTU %d] \n", mtuSet);
    }
    #else
		ATT_SetMTUSizeMax(23);
		llInitFeatureSet2MPHY(FALSE);
		llInitFeatureSetDLE(FALSE);
    #endif
    // Setup a delayed profile startup
    osal_set_event( ota_TaskID, OTA_START_DEVICE_EVT );
	LOG("======================OTA_Init Done====================\n");
}

/*********************************************************************
 * @fn      otaApp_ProcessEvent
 *
 * @brief   OTA Application Task event processor.  This function
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   task_id  - The OSAL assigned task ID.
 * @param   events - events to process.  This is a bit map and can
 *                   contain more than one event.
 *
 * @return  events not processed
 */
uint16 otaApp_ProcessEvent( uint8 task_id, uint16 events )
{
    VOID task_id; // OSAL required parameter that isn't used in this function

    if ( events & SYS_EVENT_MSG )
    {
        uint8 *pMsg;

        if ( (pMsg = osal_msg_receive( ota_TaskID )) != NULL )
        {
            otaApp_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );

            // Release the OSAL message
            VOID osal_msg_deallocate( pMsg );
        }

        // return unprocessed events
        return (events ^ SYS_EVENT_MSG);
    }

    if ( events & OTA_START_DEVICE_EVT )
    {
        // Start the Device
        VOID GAPRole_StartDevice( &oatApp_PeripheralCBs );
    #if(DEFAULT_GAPBOND_MGR_ENABLE==1)
        // Start Bond Manager, 2017-11-15
		LOG("bond\r\n");
        VOID GAPBondMgr_Register( &simpleBLEPeripheral_BondMgrCBs );
    #endif
        // Set timer for first periodic event
        osal_start_timerEx( ota_TaskID, OTA_PERIODIC_EVT, OTA_PERIODIC_EVT_PERIOD );

        return ( events ^ OTA_START_DEVICE_EVT );
    }

        // notifity
  if ( events & OTA_PERIODIC_EVT )
  {
    // Restart timer
    if ( OTA_PERIODIC_EVT_PERIOD )
    {
      osal_start_timerEx( ota_TaskID, OTA_PERIODIC_EVT, OTA_PERIODIC_EVT_PERIOD );
    }

    // Perform periodic application task
    performPeriodicTask();

    return (events ^ OTA_PERIODIC_EVT);
  }

    // Discard unknown events
    return 0;
}

/*********************************************************************
 * @fn      simpleBLEPeripheral_ProcessOSALMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static void otaApp_ProcessOSALMsg( osal_event_hdr_t *pMsg )
{
    switch ( pMsg->event )
    {  
    default:
        // do nothing
        break;
    }
}

void _Ble_GapStateChanged(gaprole_States_t newState);
/*********************************************************************
 * @fn      peripheralStateNotificationCB
 *
 * @brief   Notification from the profile of a state change.
 *
 * @param   newState - new state
 *
 * @return  none
 */
static void peripheralStateNotificationCB( gaprole_States_t newState )
{
    switch ( newState )
    {
        case GAPROLE_STARTED:
        {
            uint8 ownAddress[B_ADDR_LEN];
            uint8 systemId[DEVINFO_SYSTEM_ID_LEN];
            uint8 initial_advertising_enable = TRUE;//true
        
            GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress);
        
            // use 6 bytes of device address for 8 bytes of system ID value
            systemId[0] = ownAddress[0];
            systemId[1] = ownAddress[1];
            systemId[2] = ownAddress[2];
        
            // set middle bytes to zero
            systemId[4] = 0x00;
            systemId[3] = 0x00;
        
            // shift three bytes up
            systemId[7] = ownAddress[5];
            systemId[6] = ownAddress[4];
            systemId[5] = ownAddress[3];
        
            DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);

            GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable );
			
			LOG("MAC address:%02X:%02X:%02X:%02X:%02X:%02X\n",ownAddress[5],ownAddress[4],ownAddress[3],ownAddress[2],ownAddress[1],ownAddress[0]);
        }
            break;
        
        case GAPROLE_ADVERTISING:
            LOG("Advertising\n");
            break;
        
        case GAPROLE_CONNECTED:
			LOG("Connected\n");
			uint8 buf[7];
			GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR_TYPE,buf);
		    GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR,&buf[1]);
		    LOG("addrType=%d,addr=%x:%x:%x:%x:%x:%x",buf[0], buf[1],buf[2],buf[3],buf[4],buf[5],buf[6]);
            break;
        
        case GAPROLE_CONNECTED_ADV:
			LOG("Connected Advertising\n");
            break;      
        case GAPROLE_WAITING:
			LOG("Disconnected\n");
            break;
        
        case GAPROLE_WAITING_AFTER_TIMEOUT:
			LOG("Timed Out\n");
            break;
        
        case GAPROLE_ERROR:
			LOG("Error\n");
            break;
        
        default:
            break;        
    }  
    gapProfileState = newState;

    LOG("[GAP ROLE %d]\n",newState);
     
    VOID gapProfileState;     

    _Ble_GapStateChanged(newState);
}

/*********************************************************************
 * @fn      performPeriodicTask
 *
 * @brief   Perform a periodic application task. This function gets
 *          called every five seconds as a result of the SBP_PERIODIC_EVT
 *          OSAL event. In this example, the value of the third
 *          characteristic in the SimpleGATTProfile service is retrieved
 *          from the profile, and then copied into the value of the
 *          the fourth characteristic.
 *
 * @param   none
 *
 * @return  none
 */
static void performPeriodicTask( void )
{
	
}

/*********************************************************************
*********************************************************************/
